﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StringDefs.Typos
{
    /// <summary>
    /// This namespace holds methods 
    /// </summary>
    public static  class Typos
    {
        #region "Containers"
        public static Dictionary<char, string> PhoneticKeyMap = new Dictionary<char, string>();
        public static Dictionary<char, string> MissedKeyMap = new Dictionary<char, string>();
        public static Dictionary<string, List<string>> TypoMap = new Dictionary<string, List<string>>();
        #endregion


        #region "Private Methods"
        /// <summary>
        /// 
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        private static List<string> RemoveSpacesGradually(string phrase)
        {
            List<string> Typos = new List<string>();
            List<int> SpaceIndices = new List<int>();

            for (int i = 0; i < phrase.Length; i++)
            {
                if (phrase[i] == ' ')
                    SpaceIndices.Add(i);
            }
            if (SpaceIndices.Count > 1)
            {
                foreach (int i in SpaceIndices)
                    Typos.Add(phrase.Remove(i, 1));
            }
            return Typos;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="skipIndex"></param>
        /// <returns></returns>
        private static string SkipThisLetter(string word, int skipIndex)
        {
            StringBuilder sb = new StringBuilder();
            int i = 0;
            foreach (char c in word.ToCharArray())
            {
                if (i != skipIndex)
                    sb.Append(c.ToString());
                i++;
            }
            return sb.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        private static  string DoubleThisLetter(string word, int index)
        {
            StringBuilder sb = new StringBuilder();
            int i = 0;
            foreach (char c in word.ToCharArray())
            {
                if (i == index)
                    sb.Append(c.ToString() + c.ToString());
                else
                    sb.Append(c.ToString());
                i++;
            }
            return sb.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        private static string ReverseThisPair(string word, int first, int second)
        {
            StringBuilder sb = new StringBuilder();
            char[] CharWord = word.ToCharArray();
            char c = CharWord[first];
            CharWord[first] = CharWord[second];
            CharWord[second] = c;

            foreach (char k in CharWord)
                sb.Append(k.ToString());

            return sb.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="letterIndex"></param>
        /// <returns></returns>
        /// 
        public static void InitMissedKeyMap()
        {
            MissedKeyMap.Add('a', "q,w,s,x,z");
            MissedKeyMap.Add('b', "v,g,h,n");
            MissedKeyMap.Add('c', "x,d,f,v");
            MissedKeyMap.Add('d', "s,e,r,f,c,x");
            MissedKeyMap.Add('e', "w,3,4,r,f,d,s");
            MissedKeyMap.Add('f', "d,r,t,g,v,c");
            MissedKeyMap.Add('g', "f,t,y,h,b,v");
            MissedKeyMap.Add('h', "g,y,u,j,n,b");
            MissedKeyMap.Add('i', "u,8,9,o,l,k,j");
            MissedKeyMap.Add('j', "h,u,i,k,m,n");
            MissedKeyMap.Add('k', "j,i,o,l,m");
            MissedKeyMap.Add('l', "k,o,p");
            MissedKeyMap.Add('m', "n,j,k");
            MissedKeyMap.Add('n', "b,h,j,m");
            MissedKeyMap.Add('o', "i,9,0,p,l,k");
            MissedKeyMap.Add('p', "o,0,l");
            MissedKeyMap.Add('q', "1,2,w,s,a");
            MissedKeyMap.Add('r', "e,4,5,t,g,f,d");
            MissedKeyMap.Add('s', "a,w,e,d,x,z");
            MissedKeyMap.Add('t', "r,5,6,y,h,g,f");
            MissedKeyMap.Add('u', "y,7,8,i,k,j,h");
            MissedKeyMap.Add('v', "c,f,g,b");
            MissedKeyMap.Add('w', "q,2,3,e,d,s,a");
            MissedKeyMap.Add('x', "z,s,d,c");
            MissedKeyMap.Add('y', "t,6,7,u,j,h,g");
            MissedKeyMap.Add('z', "a,s,x");

            MissedKeyMap.Add('A', "Q,W,S,X,Z");
            MissedKeyMap.Add('B', "V,G,H,N");
            MissedKeyMap.Add('C', "X,D,F,V");
            MissedKeyMap.Add('D', "S,E,R,F,C,X");
            MissedKeyMap.Add('E', "W,3,4,R,F,D,S");
            MissedKeyMap.Add('F', "D,R,T,G,V,C");
            MissedKeyMap.Add('G', "F,T,Y,H,B,V");
            MissedKeyMap.Add('H', "G,Y,U,J,N,B");
            MissedKeyMap.Add('I', "U,8,9,O,L,K,J");
            MissedKeyMap.Add('J', "H,U,I,K,M,N");
            MissedKeyMap.Add('K', "J,I,O,L,M");
            MissedKeyMap.Add('L', "K,O,P");
            MissedKeyMap.Add('M', "N,J,K");
            MissedKeyMap.Add('N', "B,H,J,M");
            MissedKeyMap.Add('O', "I,9,0,P,L,K");
            MissedKeyMap.Add('P', "O,0,L");
            MissedKeyMap.Add('Q', "1,2,W,S,A");
            MissedKeyMap.Add('R', "E,4,5,T,G,F,D");
            MissedKeyMap.Add('S', "A,W,E,D,X,Z");
            MissedKeyMap.Add('T', "R,5,6,Y,H,G,F");
            MissedKeyMap.Add('U', "Y,7,8,I,K,J,H");
            MissedKeyMap.Add('V', "C,F,G,B");
            MissedKeyMap.Add('W', "Q,2,3,E,D,S,A");
            MissedKeyMap.Add('X', "Z,S,D,C");
            MissedKeyMap.Add('Y', "T,6,7,U,J,H,G");
            MissedKeyMap.Add('Z', "A,S,X");

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="letterIndex"></param>
        /// <returns></returns>
        private static  List<string> GetNeighbourTyposForThisLetter(string word, int letterIndex)
        {   
            List<string> Typos = new List<string>();
            StringBuilder sb = new StringBuilder();
            char c = word[letterIndex];
            string n = string.Empty;
            if (MissedKeyMap.TryGetValue(c, out n))
            {
                string[] neighbours = n.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                word = word.Remove(letterIndex, 1);
                word = word.Insert(letterIndex, "*");
                foreach (string l in neighbours)
                    Typos.Add(word.Replace("*", l));


            }
            return Typos;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="letterIndex"></param>
        /// <returns></returns>
        private static List<string> GetInsertedKeyTyposForThisLetter(string word, int letterIndex)
        {
            List<string> Typos = new List<string>();
            StringBuilder sb = new StringBuilder();
            char c = word[letterIndex];
            string n = string.Empty;
            if (MissedKeyMap.TryGetValue(c, out n))
            {
                string[] neighbours = n.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                foreach (string l in neighbours)
                {
                    //sb.AppendLine(word.Insert(letterIndex, l));
                    //sb.AppendLine(word.Insert(letterIndex + 1, l));

                    Typos.Add(word.Insert(letterIndex, l));
                    Typos.Add(word.Insert(letterIndex + 1, l));

                }
            }
            return Typos;
        }
        /// <summary>
        /// 
        /// </summary>
        public static void InitPhoneticKeyMap()
        {
            PhoneticKeyMap.Add('a', "e,o,u");
            PhoneticKeyMap.Add('e', "a,i");
            PhoneticKeyMap.Add('i', "y,e");
            PhoneticKeyMap.Add('o', "u,a");
            PhoneticKeyMap.Add('u', "o");
            PhoneticKeyMap.Add('y', "i");

            PhoneticKeyMap.Add('A', "E,O,U");
            PhoneticKeyMap.Add('E', "A,I");
            PhoneticKeyMap.Add('I', "Y,E");
            PhoneticKeyMap.Add('O', "U,A");
            PhoneticKeyMap.Add('U', "O");
            PhoneticKeyMap.Add('Y', "I");

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="word"></param>
        /// <param name="letterIndex"></param>
        /// <returns></returns>
        private static List<string> GetPhoneticKeyTypoForThisLetter(string word, int letterIndex)
        {
            
            List<string> Typos = new List<string>();
            StringBuilder sb = new StringBuilder();
            char c = word[letterIndex];
            string n = string.Empty;
            if (PhoneticKeyMap.TryGetValue(c, out n))
            {
                string[] neighbours = n.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                word = word.Remove(letterIndex, 1);
                word = word.Insert(letterIndex, "*");
                foreach (string l in neighbours)
                    // sb.AppendLine(word.Replace("*", l));
                    // sb.Append(word.Replace("*", l));
                    Typos.Add(word.Replace("*", l));

            }
            return Typos;
        }
        #endregion

        #region "Public Methods"
        /// <summary>
        /// Finds Typing errors due to skipped spaces
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        public static List<string> GetSkipSpaceTypos(this string phrase)
        {
            List<string> Typos = new List<string>();
            Typos.AddRange(RemoveSpacesGradually(phrase));
                Typos.Add(phrase.Replace(" ", string.Empty));
            return Typos;
        }
        /// <summary>
        /// Finds Typos due to skipped letters 
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        public static List<string> GetSkipLetterTypos(this string phrase)
        {
            List<string> Typos = new List<string>();
            for (int i = 0; i < phrase.Length; i++)
            {
                string temp = SkipThisLetter(phrase, i);
                //lstTypos.Items.Add(temp + Environment.NewLine);
                if (temp != "")
                    Typos.Add(temp);

            }
            return Typos;
        }

        /// <summary>
        /// Finds typos due to reversed letters
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        public static List<string> GetReverseLettersTypos(this string phrase)
        {
            List<string> Typos = new List<string>();
            for (int i = 0; i < phrase.Length - 1; i++)
            {
               string temp = ReverseThisPair(phrase, i, i + 1);
               if (temp != "")
                  Typos.Add(temp);
                    
            }
           return Typos;
        }
        /// <summary>
        /// Finds typos due to Missed Key
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        public static List<string> GetMissedKeyTypos(this string phrase)
        {
            List<string> Typos = new List<string> ();
            for (int i = 0; i < phrase.Length; i++)
            {
                Typos.AddRange(GetNeighbourTyposForThisLetter(phrase, i));
            }
            return Typos;
        }
        /// <summary>
        /// Finds Typos due to inserted keys
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        public static List<string> GetInsertedKeyTypos (this string phrase)
        {
            List<string> Typos = new List<string>();
            for (int i = 0; i < phrase.Length; i++)
                Typos.AddRange(GetInsertedKeyTyposForThisLetter(phrase, i));

            return Typos;
         }
        /// <summary>
        /// Find Typos due to closely phonetically attatched keys
        /// </summary>
        /// <param name="phrase"></param>
        /// <returns></returns>
        public static List<string> GetPhoneticKeyTypos(this string phrase)
        {
            List<string> Typos = new List<string>();
            for (int i = 0; i < phrase.Length; i++)
            {
                Typos.AddRange(GetPhoneticKeyTypoForThisLetter(phrase, i));
            }
            return Typos ;
        }

        #endregion
    }
}
